﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Media;
using System.IO;
using Microsoft.Xna.Framework.Graphics;
using System.Collections;
using Aim2.Screen;

namespace Aim2.Music {
    public class Track : IObjectContainer {
        public string Title { get; set; }
        public string Artist { get; set; }
        public string Genre { get; set; }
        public TimeSpan Duration { get; set; }

        float offset;
        float BPM;

        public int MeasureCount { get { return measureCount; } }
        int measureCount;

        float totalElapsed;
        public float TotalNeeded { get; set; }

        Queue<Measure> measures;
        Measure currentMeasure;

        List<AnimatedObject> liveElements;
        Stack<AnimatedObject> ToRemove;

        public Track(Song song, DirectoryInfo folder) {
            liveElements = new List<AnimatedObject>();
            ToRemove = new Stack<AnimatedObject>();
            measures = new Queue<Measure>();
            LoadFile(folder);
            totalElapsed = offset;
            TotalNeeded = 60f / BPM;
            currentMeasure = measures.Dequeue();
            measureCount = 1;
            CollisionManager.Instance.Register(this);
        }

        public void Update(float elapsed) {
            totalElapsed += elapsed;
            if (totalElapsed >= TotalNeeded && measures.Count > 0) {
                currentMeasure = measures.Dequeue();
                measureCount++;
                totalElapsed = 0;
            }
            if (currentMeasure.Full || currentMeasure.IsNextReady(elapsed) && currentMeasure.Count > 0) {
                string code = currentMeasure.Dequeue();
                string[] elements = code.Split('|');
                for(int i = 0 ; i < elements.Count(); i ++) {
                    switch (Translator.Analyze(elements[i])) {
                        case AIMCode.LiveElement:
                            liveElements.Add(Translator.TranslateElement(elements[i], this));
                            break;
                        case AIMCode.ChangeColor:
                            var t = Translator.GetColorChange(elements[i]);
                            ScreenManager.ChangeBackgroundColors(t.Item1, t.Item2, t.Item3 * TotalNeeded);
                            break;
                        case AIMCode.ChangeRotation:
                            ScreenManager.ChangeTilesRotation(Translator.GetBool(elements[i]));
                            break;
                        case AIMCode.ChangeBarsSize:
                            ScreenManager.InitTransitionBarsSize(Translator.GetBeats(elements[i]) * TotalNeeded, Translator.GetFloat(elements[i]));
                            break;
                        case AIMCode.ChangeTilesSpeed:
                            ScreenManager.InitTransitionTilesSpeed(Translator.GetBeats(elements[i]) * TotalNeeded, Translator.GetFloat(elements[i]));
                            break;
                        case AIMCode.ChangeTilesSizeX:
                            ScreenManager.InitTransitionTilesSizeX(Translator.GetBeats(elements[i]) * TotalNeeded, Translator.GetFloat(elements[i]));
                            break;
                        case AIMCode.ChangeTilesSizeY:
                            ScreenManager.InitTransitionTilesSizeY(Translator.GetBeats(elements[i]) * TotalNeeded, Translator.GetFloat(elements[i]));
                            break;
                        case AIMCode.ChangeBarsNumber:
                            ScreenManager.ChangeBarsNumber(Translator.GetInt(elements[i]));
                            break;
                        case AIMCode.ChangeBarFormula:
                            ScreenManager.ChangeBarFormula((BarFormula) Translator.GetInt(elements[i]));
                            break;
                        case AIMCode.ChangeBarSizeFormula:
                            ScreenManager.ChangeBarSizeFormula(Translator.GetBool(elements[i]));
                            break;
                    }
                }
                
            }
            foreach (AnimatedObject a in liveElements)
                a.Update(elapsed);
        }

        public void Draw(SpriteBatch spriteBatch) {
            foreach (AnimatedObject a in liveElements)
                a.Draw(spriteBatch);
        }

        public void Remove(AnimatedObject a) {
            liveElements.Remove(a);
        }

        private void LoadFile(DirectoryInfo folder) {
            measures.Clear();
            using (StreamReader sr = new StreamReader(folder.GetFiles("*.aim")[0].FullName)) {
                Title = sr.ReadLine().Split('=')[1];
                Artist = sr.ReadLine().Split('=')[1];
                Genre = sr.ReadLine().Split('=')[1];
                offset = (float)Convert.ToDouble(sr.ReadLine().Split('=')[1]);
                Duration = TimeSpan.Parse(sr.ReadLine().Split('=')[1]);
                BPM = (float) Convert.ToDouble(sr.ReadLine().Split('=')[1]);

                Measure currentMeasure = new Measure(BPM);
                while (!sr.EndOfStream) {
                    string line;
                    while ((line = sr.ReadLine()) == String.Empty) ;

                    if (line == ",") {
                        measures.Enqueue(currentMeasure);
                        currentMeasure = new Measure(BPM);
                    }
                    else
                        currentMeasure.Enqueue(line);
                }
            }
        }


        public IEnumerator<AnimatedObject> GetEnumerator() {
            foreach (AnimatedObject a in liveElements)
                yield return a;
        }

        IEnumerator IEnumerable.GetEnumerator() {
            return GetEnumerator();
        }
        public void AddToRemovalList(AnimatedObject a) {
            ToRemove.Push(a);
        }

        public void RemovePending() {
            AnimatedObject a;
            while (ToRemove.Count > 0) {
                a = ToRemove.Pop();
                liveElements.Remove(a);
            }
        }
    }
}
